package mysqls

import (
	"errors"
	"qingbing/xzutils/structs"
	"qingbing/xzutils/tools"

	"gorm.io/gorm"
)

/*
 * 新建 DBModel
 */
func NewModel(db ...*gorm.DB) *DBModel {
	if len(db) == 0 {
		return &DBModel{DB: DB}
	}
	return &DBModel{DB: db[0]}
}

/*
 * DBModel 结构体
 */
type DBModel struct {
	*gorm.DB
}

/*
 * 判断返回错误是否是 ErrRecordNotFound
 */
func (DBModel) ErrorIsRecordNotFound(err error) bool {
	return errors.Is(err, ErrRecordNotFound)
}

/*
 * 判断返回错误是否是 ErrRecordNotFound
 */
func (dm *DBModel) Tx() *gorm.DB {
	if dm.DB == nil {
		return DB
	}
	return dm.DB
}

/*
 * 设置数据表的 Model
 */
func (dm *DBModel) SetModel(mod any) *DBModel {
	dm.DB = dm.Tx().Model(mod)
	return dm
}

/*
 * 创建数据
 */
func (dm *DBModel) Insert(mod any) any {
	if tx := dm.Tx().Create(mod); tx.Error != nil {
		panic(tx.Error)
	}
	return mod
}

/*
 * 根据结构体创建数据
 */
func (dm *DBModel) InsertByStruct(mod any, params any) any {
	// 模型赋值
	structs.ToStruct(mod, params)
	// 插入数据
	return dm.Insert(mod)
}

/*
 * 保存数据
 */
func (dm *DBModel) Save(mod any) any {
	if tx := dm.Tx().Save(mod); tx.Error != nil {
		panic(ErrSaveFailed)
	}
	return mod
}

/*
 * 根据结构体创建数据
 */
func (dm *DBModel) SaveByStruct(mod any, params any) any {
	// 模型赋值
	structs.ToStruct(mod, params)
	// 保存数据
	return dm.Save(mod)
}

/*
 * 删除数据
 */
func (dm *DBModel) Delete(mod any, conds ...interface{}) any {
	if tx := dm.Tx().Delete(mod, conds...); tx.Error != nil {
		panic(ErrDeletedFailed)
	}
	return mod
}

/*
 * 查询单条数据
 */
func (dm *DBModel) Take(dest any, conds ...interface{}) any {
	if tx := dm.Tx().Take(dest, conds...); tx.Error != nil {
		if dm.ErrorIsRecordNotFound(tx.Error) {
			return nil
		}
		panic(ErrQueryFailed)
	}
	return dest
}

/*
 * 查询满足条件的多条数据
 */
func (dm *DBModel) Find(dest any, conds ...interface{}) any {
	if tx := dm.Tx().Find(dest, conds...); tx.Error != nil && !dm.ErrorIsRecordNotFound(tx.Error) {
		panic(ErrQueryFailed)
	}
	return dest
}

/*
 * 查询单条数据, 如果查询有条件, 需要在 tx 中设置好
 */
func (dm *DBModel) TakeByTx(dest any, tx *gorm.DB) interface{} {
	tx = tx.Take(dest)
	if tx.Error != nil {
		if dm.ErrorIsRecordNotFound(tx.Error) {
			return nil
		}
		panic(ErrQueryFailed)
	}
	return dest
}

/*
 * 查询满足条件的多条数据, 如果查询有条件, 需要在 tx 中设置好
 */
func (dm *DBModel) FindByTx(dest any, tx *gorm.DB) interface{} {
	if tx = tx.Find(dest); tx.Error != nil && !dm.ErrorIsRecordNotFound(tx.Error) {
		panic(ErrQueryFailed)
	}
	return dest
}

/*
 * 模型
 */
// 自增ID
type ModelID struct {
	ID uint `json:"id"    gorm:"type:bigint(20) unsigned NOT NULL;primaryKey;comment:自增ID"`
}

// 用户ID
type ModelUID struct {
	UID uint `json:"uid"    gorm:"type:bigint unsigned NOT NULL;default:0;comment:用户ID;index"`
}

type ModelSex struct {
	Sex string `json:"sex"    gorm:"type:enum('1', '2', '3') NOT NULL;default:'1';comment:性别[1:密,2:男,3:女]"`
}

// 手机号码: Mobile
type ModelMobile struct {
	Mobile string `json:"mobile"    gorm:"type:varchar(15) NOT NULL;default:'';comment:手机号码"`
}

// 邮箱: Email
type ModelEmail struct {
	Email string `json:"email"    gorm:"type:varchar(100) NOT NULL;default:'';comment:邮箱;email"`
}

// 固定电话: Phone
type ModelPhone struct {
	Phone string `json:"phone"    gorm:"type:varchar(15) NOT NULL;default:'';comment:固定电话"`
}

// 主键: Code
type ModelCode struct {
	Code string `json:"code"  gorm:"type:varchar(50) NOT NULL;default:'';comment:标记;index"`
}

// 创建字段
type ModelCreatedAt struct {
	CreatedAt tools.Time `json:"created_at"    gorm:"type:datetime NOT NULL;default:CURRENT_TIMESTAMP;comment:创建时间"`
}

// 更新字段
type ModelUpdatedAt struct {
	UpdatedAt tools.Time `json:"updated_at"    gorm:"type:datetime NOT NULL;default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;comment:更新时间"`
}

// 删除字段
type ModelDeletedAt struct {
	DeletedAt gorm.DeletedAt `json:"-"    gorm:"type:datetime;comment:删除时间;index"`
}

// 排序
type ModelSortOrder struct {
	SortOrder uint8 `json:"sort_order"    gorm:"type:tinyint(8) NOT NULL;default:0;comment:排序;index"`
}

// 操作ip
type ModelIp struct {
	Ip string `json:"ip"    gorm:"type:varchar(15) NOT NULL;comment:操作IP"`
}

// 启用
type ModelIsEnabled struct {
	IsEnabled bool `json:"is_enabled"    gorm:"type:tinyint(1) unsigned NOT NULL;default:0;comment:启用状态;index"`
}

// 通用
type ModelIsPublic struct {
	IsPublic bool `json:"is_public"    gorm:"type:tinyint(1) unsigned NOT NULL;default:0;comment:是否通用;index;"`
}

// 描述
type ModelDescription struct {
	Description string `json:"description"    gorm:"type:varchar(255) NOT NULL;default:'';comment:描述"`
}

// json 数据
type ModelJsonData struct {
	Data map[string]any `json:"data"    gorm:"serializer:json;type:json;comment:JSON数据"`
}
